#include "ccmdparse.h"
#include "serversetting.h"
#include "clog.h"
#include "knx/knx_interface.h"
#include "knx/qt_knx.h"
#include "cmd.h"
#include "knx/cmei.h"
#include <QThread>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QFile>
#include <QTime>
#include <QDateTime>
#include "cudpcmd.h"

CCmdParse::CCmdParse(QObject *parent) :
    QObject(parent)
{
//    ttgIps = new CTTGIpsConnector(this);

//    ttgIps->setNetWork(ServerSetting::defaultSetting()->_ip,ServerSetting::defaultSetting()->_port.toUInt());
//    ttgIps->setLogInfo(ServerSetting::defaultSetting()->_user,ServerSetting::defaultSetting()->_password);

//    ttgIps->setNetWork("192.168.1.211",5006);
//    ttgIps->setLogInfo("Hinwo123","Hinwo0");

//    connect(ttgIps,SIGNAL(s_gateWayConnectState(int)),this,SLOT(doGateWayStateUpdate(int)));
//    connect(ttgIps,SIGNAL(s_valueNotify(void *,QByteArray ,void *)),this,SLOT(doGateWayValueUpdate(void *,QByteArray ,void *)));

    locolIps = new CLocolIPS(this);
    CUdpCmd::cntDelegate = locolIps;

    //server will record the gateway connect state
    //connect(locolIps,SIGNAL(s_gateWayConnectState(int)),this,SLOT(doGateWayStateUpdate(int)));
    connect(locolIps,SIGNAL(s_valueNotify(void *,QByteArray ,void *)),this,SLOT(doGateWayValueUpdate(void *,QByteArray ,void *)));
    connect(locolIps,SIGNAL(s_recordMsg(QString)),this,SLOT(doRecordUpdate(QString)));

    _refreshTimer.setInterval(200);
    connect(&_refreshTimer,SIGNAL(timeout()),this,SLOT(doRefreshObject()));
    //cmd signals & slots

    connect(&_testStatusTimer,SIGNAL(timeout()),this,SLOT(doStatusTest()));
    //_testStatusTimer.start(300);

    _gLog = CLog::getSingle();
}

CCmdParse::~CCmdParse()
{
    projectDestroy();
}

void CCmdParse::projectInit(QString jsonPath)
{
    projectDestroy();

    QFile file(jsonPath);
    if(file.open(QFile::ReadOnly))
    {
        QByteArray json = file.readAll();
        QJsonDocument jd = QJsonDocument::fromJson(json);
        if(jd.isObject())
        {
            QJsonObject jo = jd.object();
            QJsonObject::Iterator it = jo.find("devices");

            QJsonValue jdeviceValue = it.value();
            if(jdeviceValue.isObject())
            {
                QJsonObject funJsonObj = jdeviceValue.toObject();
                QJsonObject::Iterator it = funJsonObj.begin();
                qDebug() << "Iterator " << jdeviceValue.toObject().keys();
                //功能区域遍历
                while(it!=funJsonObj.end())
                {
                    QJsonValue i = it.value();
                    if(i.isArray())
                    {
                        QJsonArray devArray = i.toArray();
                        for(int d=0;d<devArray.size();d++)
                        {
                            QJsonObject obj = devArray.at(d).toObject();
                            QJsonDocument tjd;
                            tjd.setObject(obj);

                            Json_DEVICE_OBJECT *jo = new Json_DEVICE_OBJECT(tjd.toJson(),locolIps);
                            _regObjMap.insert(jo->_id,jo);

                            qDebug() << "pid - obj " << jo->_pid << " - " << jo->_id;
                        }
                    }

                    it++;
                }
            }
        }
    }

    setUpKnxObjs();

}

bool CCmdParse::projectContext(QByteArray json)
{
    projectDestroy();

    QString jsonUtf8 = QString::fromUtf8(json);
    //jsonUtf8.replace("\\","");

    QJsonDocument jd = QJsonDocument::fromJson(jsonUtf8.toLocal8Bit());
    if(jd.isArray())
    {
       QJsonArray jArray = jd.array();
       for(int i=0;i<jArray.size();i++)
       {
           QJsonValue jdeviceValue = jArray.at(i);
           if(jdeviceValue.isObject())
           {
               QJsonObject obj = jdeviceValue.toObject();

               QJsonDocument tjd;
               tjd.setObject(obj);

               Json_DEVICE_OBJECT *jo = new Json_DEVICE_OBJECT(tjd.toJson(),locolIps);
               _regObjMap.insert(jo->_id,jo);

               _audioControl.insertDeviceObject(jo);

               qDebug() << "pid - obj " << jo->_pid << " " << jo->_id;

               QThread::msleep(20);
           }
       }

       if(_regObjMap.size() > 0)
       {
            setUpKnxObjs();
            return true;
       }
    }

    return false;
}

void CCmdParse::projectDestroy()
{
    locolIps->unRegisterAll();

    if(_regObjMap.size()!=0)
    {
        QMap<QString,Json_DEVICE_OBJECT *>::Iterator it = _regObjMap.begin();
        while (it!=_regObjMap.end()) {
            Json_DEVICE_OBJECT *o = it.value();
            if(o)
                delete o;

            it++;
        }
    }

    _regObjMap.clear();
    _listReadAfterWrite.clear();
    _listRefresh.clear();
    _audioControl.clearMap();
}

void CCmdParse::setUpKnxObjs()
{
    QMap<QString,Json_DEVICE_OBJECT *>::Iterator it = _regObjMap.begin();
    while (it!=_regObjMap.end()) {
        Json_DEVICE_OBJECT *o = it.value();
        if(o && o->_regList)
        {
            for(int i=0;i<o->_regList->size();i++)
            {
                DEVICE_OBJECT *obj = o->_regList->at(i);
                locolIps->registeObject(obj,(void *)o);
            }
        }

        it++;
    }

    it = _regObjMap.begin();
    while (it!=_regObjMap.end()) {
        Json_DEVICE_OBJECT *o = it.value();
        if(o && o->_regList)
        {
            _listRefresh.append(o);
            //o->doRead();
        }

        it++;
    }

    //refresh all object status
    if(ServerSetting::defaultSetting()->_reload_knx != "0")
    {
        refreshStatus();
    }

    refreshStatus();

//    DEVICE_OBJECT *obj = new DEVICE_OBJECT();
//    obj->_address = "1/5/58";
//    obj->_data_type = ONE_BIT_VALUE;
//    obj->_data_define = UNSIGNED_INT;
//    cmei_set_group_address(obj->_ga_ia,obj->_address);

//    ttgIps->registeObject(obj,NULL);

//    obj = new DEVICE_OBJECT();
//    obj->_address = "1/5/56";
//    obj->_data_type = ONE_BIT_VALUE;
//    obj->_data_define = UNSIGNED_INT;
//    cmei_set_group_address(obj->_ga_ia,obj->_address);

//    ttgIps->registeObject(obj,NULL);
}

void CCmdParse::refreshStatus()
{
    if(_refreshTimer.isActive())
    {
        qDebug() << "refreshStatus still running...";
        return;
    }

    _listReadAfterWrite = QList<Json_DEVICE_OBJECT *>(_listRefresh);

    if(!_refreshTimer.isActive())
        _refreshTimer.start();
}

void CCmdParse::doRefreshObject()
{
    if(_listReadAfterWrite.size()>0)
    {
        qDebug() << "timer read status:" << _listReadAfterWrite.size();
        Json_DEVICE_OBJECT *o = _listReadAfterWrite.takeFirst();
        o->doRead();
    }
    else
        _refreshTimer.stop();
}

void CCmdParse::doGateWayStateUpdate(int state)
{
    QString msg = QString("@%1:%2:%3:%4:%5:%6")
                        .arg(0)
                        .arg(0)
                        .arg("gateway")
                        .arg("status")
                        .arg(ServerSetting::defaultSetting()->_ip)
                        .arg(state);

    emit s_JsonReport(msg);

}

void CCmdParse::doRecordUpdate(QString value)
{
    _gLog->logOutput(value);
    //qDebug() << "doRecordUpdate:" << str;
}

void CCmdParse::doGateWayValueUpdate(void *devObj,QByteArray value,void *userdata)
{
    DEVICE_OBJECT *o = (DEVICE_OBJECT *)devObj;
    QString sv = DEVICE_OBJECT::KnxDataToQString(o->_data_type,o->_data_define,(_u8 *)value.data(),value.size());
    QString action = "";
    if(userdata)
    {
        Json_DEVICE_OBJECT *jo = (Json_DEVICE_OBJECT *)userdata;
        action = jo->actionFromStatus(o->_address,sv);
        sv = jo->valueCheck(action,sv);

        QString msg = QString("%1:%2:%3:%4:%5:%6")
                            .arg(jo->_pid)
                            .arg(jo->_id)
                            .arg(jo->_type)
                            .arg(action)
                            .arg(QString(o->_address))
                            .arg(sv);

        emit s_deviceJsonReport(jo->_id+"-"+QString(o->_address),msg);
    }

}

void CCmdParse::doStatusTest()
{
    QList<QString> list = _regObjMap.keys();
    int size = list.size();
    if(size>0)
    {
        int r = rand() % size;
        Json_DEVICE_OBJECT *jo = _regObjMap.value(list.at(r));
       if(jo->_type == "switch" || jo->_type == "dim")
        {
            QString sv = "on";
            if(rand()%2 != 0)
                sv = "off";

            QString action = sv;
            if(jo->_type == "dim")
            {
                action = "value";
               sv = QString("%1").arg(rand()%200);
            }

            QString msg = QString("%1:%2:%3:%4:%5:%6")
                                .arg(jo->_pid)
                                .arg(jo->_id)
                                .arg(jo->_type)
                                .arg(action)
                                .arg(list.at(r))
                                .arg(sv);

           //qDebug() << "Do emit test update";^M
           emit s_deviceJsonReport(jo->_id,msg);
        }

   }

}

void CCmdParse::runningCheck()
{
    if(!locolIps->init)
        locolIps->resetChannel();
}

/*
 *  设备状态上传更新  all web app none
    "{ \"Gate_UPDATE\":\"all\" }"

*/
bool CCmdParse::anayseXmlData(QByteArray xmlData)
{
    QDomDocument domTree;
    QString errorMsg ;
    int errorLine;
    int errorColumn;

    if (!domTree.setContent( xmlData,false, &errorMsg , &errorLine , &errorColumn ) )
    {
        qDebug() << "XML格式错误,msg: " << errorMsg << "line " << errorLine;
        qDebug() << "XML data:" <<  QString(xmlData);
        return false;
    }

    QDomElement ele = domTree.documentElement();
    QString cmdStr = ele.tagName();

    qDebug() << "Gate Way Tcp read:" << xmlData;

    QWriteLocker locker(&lock);

    if(cmdStr == SET_DEV)
    {
        setDevControl(ele);
    }
    else if(cmdStr == GET_DEV)
    {
        getDevControl(ele);
    }

    return true;
}

void CCmdParse::setDevControl(QDomElement element)
{
    DATA_TYPE value_type = (DATA_TYPE)element.attributeNode("value_type").value().toUInt();
    DATA_DEFINE value_define = (DATA_DEFINE)element.attributeNode("value_define").value().toUInt();
    QString value_addr = element.attributeNode("address").value();
    QString value = element.attributeNode("value").value();

    if(!value_addr.isEmpty())
    {
        int data_len = 0;
        if((data_len = DEVICE_OBJECT::KnxQStringToData(value,value_type,value_define,(_u8 *)_data_buf)) == -1)
        {
            qDebug() << "SetDev ret='-1' msg='error data args'" ;
            return ;
        }

        cmei_set_group_address(_addr_buf,value_addr.toLocal8Bit());
        locolIps->ttg_write_device(_addr_buf,value_type,_data_buf,data_len);
    }
    else
    {
        qDebug() << "MSG_ADDR isEmpty" ;
    }

}

void CCmdParse::getDevControl(QDomElement element)
{
    QString value_addr = element.attributeNode("address").value();
    int id = element.attributeNode("id").value().toInt();

    if(!value_addr.isEmpty())
    {
        cmei_set_group_address(_addr_buf,value_addr.toLocal8Bit());
        locolIps->ttg_read_status(_addr_buf);
    }
}

// json
///////////////////////////////////////////////////////////////////////

QByteArray CCmdParse::anayseJsonData(QByteArray jsonData)
{
    QJsonDocument domTree = QJsonDocument::fromJson(jsonData);

    if (domTree.isNull() || domTree.isEmpty())
    {
        qDebug() << "Json 格式错误: " << jsonData;
        return "";
    }

    if(domTree.isObject())
    {
        QJsonObject jobj = domTree.object();
        QString cmdStr = "";

        QJsonObject::Iterator it = jobj.begin();
        while (it != jobj.end()) {
            cmdStr = it.key();

            if(it.value().type() == QJsonValue::Object)
            {
                QJsonObject obj = it.value().toObject();

                if(cmdStr == SET_DEV)
                {
                    setDevControlJson(obj);
                }
                else if(cmdStr == GET_DEV)
                {
                    getDevControlJson(obj);
                }
                else if(cmdStr == UPDATE_DEV)
                {
                    updateDevJson(obj);
                }
                else if(cmdStr == SET_VOICE)
                {
                    updateVoiceJson(obj);
                }
                else if(cmdStr == MSG_DEV){
                    return setDevMsg(obj).toLocal8Bit();
                }
            }

            it++;
        }
    }
    else if(domTree.isArray())
    {
        QJsonArray array = domTree.array();
        if(array.size()>0){
            QJsonObject audio_obj = array.at(0).toObject();
            QString M_Response = audio_obj.value("M_Response").toString();
            QJsonDocument jdoc;

            if(M_Response.isEmpty())
            {
                jdoc.setObject(audio_obj);
                return jdoc.toJson();
            }
            else
            {
                int ret = doAudioParse(jsonData);
                if(ret == 0){
                    jdoc.setObject(audio_obj);
                    return jdoc.toJson();
                }
                else
                {
                    //0.无疑问结果, 2.解析失败, 3未有合适项, 4.场景匹配结果， 5.未指定设备名结果
                    switch (ret) {
                    case 2:
                        audio_obj.remove("M_Response");
                        audio_obj.insert("M_Response","无法解析相关指令");
                        break;
                    case 3:
                        audio_obj.remove("M_Response");
                        audio_obj.insert("M_Response","没有找到相关设备");
                        break;
                    case 5:
                        audio_obj.remove("M_Response");
                        audio_obj.insert("M_Response","请指定相关设备");
                        break;
                    default:
                        audio_obj.remove("M_Response");
                        audio_obj.insert("M_Response","未知指令");
                        break;
                    }

                    jdoc.setObject(audio_obj);
                    return jdoc.toJson();
                }
            }
        }
    }

    return "";
}

QString CCmdParse::setDevMsg(QJsonObject element)
{
    QString cmd = element.value("cmd").toString();
    QStringList args = element.value("args").toString().split(",");

    bool r = _execCmd.doCmd(cmd,args);
    if(r){
        return cmd;
    }else{
        return "fail";
    }
}

void CCmdParse::updateVoiceJson(QJsonObject element)
{
    QString word;
    int type,caller;

    type = element.value("type").toInt();
    caller = element.value("caller").toInt();
    word = element.value("word").toString();


    _audioControl.doParseAttention(word);

//    QList<ADDataType> results = ADApi::ParseAttention(word, status_code, -10000, "", "http://120.76.205.173:8090/chat");
//    for(int i=0; i<results.size(); i++)
//    {
//        results[i].PrintOutInfo();
//        qDebug()<<"--";
//    }
}

void CCmdParse::setDevControlJson(QJsonObject element)
{
    QString id,type,action,value;
    id = element.value("id").toString();
    type =  element.value("type").toString();
    action = element.value("action").toString();
    value = element.value("state_value").toString();

    Json_DEVICE_OBJECT *obj = _regObjMap.value(id);
    if(obj)
    {
        obj->doAction(action,value);
    }
}

void CCmdParse::updateDevJson(QJsonObject element)
{
    QString mode = element.value("mode").toString();
    emit s_updateMode(mode);
}

int CCmdParse::doAudioParse(QByteArray bytes)
{
    return _audioControl.doParseVoice(bytes);
}

void CCmdParse::getDevControlJson(QJsonObject element)
{
    QString id = element.value("id").toString();
    if(id.toInt() == -1)
    {
        emit s_controlCmd(CMD_CONTROL_READ_ALL);
    }
    else {

        Json_DEVICE_OBJECT *obj = _regObjMap.value(id);
        if(obj)
        {
            qDebug() << "Json read cmd: " << obj->_id;
            obj->doRead();
        }
    }
}
